Thank you for your revert Claude.
As far as I see, connection is a requirement for scanning BLE devices in the background.
Post
Replies
Boosts
Views
Activity
I have made the "func getWeatherData" global like "func fetchWeather" and I'm still getting the same error. I can e-mail you the project.
onurduzova@gmail.com
I took the "fetchWeather" out of the "class ViewModel" and I'm still getting the same error.
public func fetchWeather(cityName: String) {
let urlString = "\(ViewModel().weatherURL)&query=\(cityName)"
ViewModel().getWeatherData(with: urlString)
}
struct SearchBar: UIViewRepresentable {
@Binding var text: String
class Coordinator: NSObject, UISearchBarDelegate {
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
fetchWeather(cityName: text)
}
}
Thank your for your guidance but I'm having trouble with accessing "fetchWeather" in "class ViewModel" from "class Coordinator" because "class Coordinator" is within the "struct SearchBar" and therefore I can't subclass such as "class Coordinator: ViewModel". In line "13" I'm getting the "Use of unresolved identifier 'ViewModel' " error.
Would you have any suggestion regarding the accessibility ?
struct SearchBar: UIViewRepresentable {
@Binding var text: String
class Coordinator: NSObject, UISearchBarDelegate {
@ObservedObject var viewModel = ViewModel()
@Binding var text: String
init(text: Binding<String>) {
_text = text
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
viewModel.fetchWeather(cityName: text)
}
}
class ViewModel: ObservableObject {
func fetchWeather(cityName: String) {
let urlString = "\(weatherURL)&query=\(cityName)"
getWeatherData(with: urlString)
}
}
Thanks very much Claude.
I first tried with the outlet but the result didn't change. I added the "Spinner.stop()" in "func spinnerSetup()" before the segue. But the outcome remains the same.import UIKit
class StitchEffectViewController: UIViewController {
// @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
let stitchPhotoID = "StitchPhotoID"
@IBOutlet weak var tapAboveOutlet: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// activityIndicator.isHidden = true
// activityIndicator.hidesWhenStopped = true
}
// override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
// super.viewWillTransition(to: size, with: coordinator)
//
// if UIApplication.shared.applicationState == .inactive {
// Spinner.update()
// }
//
// }
@IBAction func tapAbove(_ sender: UIButton) {
Spinner.start(style: .large, backColor: UIColor.white, baseColor: UIColor.green)
spinnerSetup()
}
func spinnerSetup() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
Spinner.stop()
self.performSegue(withIdentifier: self.stitchPhotoID, sender: nil)
})
}
}
Hi Claude, yes I expect that because all the photo effects and objc funcs are slowing the app down. Regarding the block, I've been trying to make the activityIndicator(Spinner.start) to show up before the app freezes due to the segue operation. The activityIndicator shows up after the segue on the next viewController making that viewController irresponsive. import Foundation
import UIKit
open class Spinner {
internal static var spinner: UIActivityIndicatorView?
public static var style: UIActivityIndicatorView.Style = .large
public static var baseBackColor = UIColor(white: 0, alpha: 0.6)
public static var baseColor = UIColor.red
public static func start(style: UIActivityIndicatorView.Style = style, backColor: UIColor = baseBackColor, baseColor: UIColor = baseColor) {
if spinner == nil, let window = UIApplication.shared.windows.filter({$0.isKeyWindow}).first {
let frame = UIScreen.main.bounds
spinner = UIActivityIndicatorView(frame: frame)
spinner!.backgroundColor = backColor
spinner!.style = style
spinner?.color = baseColor
window.addSubview(spinner!)
spinner!.startAnimating()
// NotificationCenter.default.addObserver(self, selector: #selector(update), name: NSNotification.Name.AVCaptureDeviceWasDisconnected, object: nil)
}
}
public static func stop() {
if spinner != nil {
spinner!.stopAnimating()
spinner!.removeFromSuperview()
spinner = nil
}
}
// @objc public static func update() {
// if Spinner.spinner != nil {
// Spinner.stop()
// Spinner.start()
// }
// }
}
Thank you very much, have a great weekend !
Hi Claude, thank you for your response. Regarding the call of "applyFilterTo".@objcprivatefunc sliderNoiseDidChange(_ sender: UISlider!, image: UIImage,_ event: UIEvent) {
if let touchEvent = event.allTouches?.first {
switch touchEvent.phase {
case .moved:
labelControl.text = String(displayInPercentage)
if updatedImage == nil {
updatedImage = effects.applyFilterTo(image: pickedImage!, filterEffect: Effects.Filter(filterName: "CIUnsharpMask", filterEffectValue: nil, filterEffectValueName: nil), sliderValue: CGFloat(sender.value))
} else {
updatedImage = effects.applyFilterTo(image: updatedImage!, filterEffect: Effects.Filter(filterName: "CIUnsharpMask", filterEffectValue: nil, filterEffectValueName: nil), sliderValue: CGFloat(sender.value))
}
case .ended:
if segmentedControl.selectedSegmentIndex == 3 {
updatedImage = photoImageView.image
UserDefaults.standard.setValue(sliderControl.value, forKey: "slider_noise")
}
default:
break
}
}
labelControl.textAlignment = .center
labelControl.numberOfLines = 0
labelControl.textColor = UIColor.gray
labelControl.font = UIFont.systemFont(ofSize: 16)
labelControl.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(labelControl)
NSLayoutConstraint.activate([labelControl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30),
labelControl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
labelControl.bottomAnchor.constraint(equalTo: resetConfirmCollectionView.topAnchor, constant: -80)])
}
Following up on the changes, I get this error in the console; (That actually happens from time to time, I really hope so.)[UICollectionView] Invalid update: invalid number of items in section 0. The number of items contained in an existing section after the update (2) must be equal to the number of items contained in that section before the update (2), plus or minus the number of items inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of items moved into or out of that section (0 moved in, 0 moved out). - will perform reloadData. UICollectionView instance: <UICollectionView: 0x7fa54789d400; frame = (0 742; 375 70); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600000337660>; layer = <CALayer: 0x600000dcf6e0>; contentOffset: {0, 0}; contentSize: {375, 133.75}; adjustedContentInset: {0, 0, 34, 0}; layout: <UICollectionViewFlowLayout: 0x7fa54663f890>; dataSource: <"appName".PhotoViewController: 0x7fa54666bc50>>; currentUpdate: [UICollectionViewUpdate - 0x7fa546662ef0: old:<UICollectionViewData: 0x60000343dc00> new<UICollectionViewData: 0x600003433b80> items:<( "I(0,0)")>]func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == resetConfirmCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResetConfirmCellID", for: indexPath) as! ResetConfirmCell
let config = UIImage.SymbolConfiguration(pointSize: 40, weight: .semibold)
if indexPath.row == 0 {
guard let cellImage = UIImage(systemName: "multiply", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
if dataPassed?.row == 1 {
let cellCount = resetConfirmCollectionView.visibleCells.count
let item = cellCount - 1
let cellIndexPath = IndexPath(item: item, section: 0)
resetConfirmCollectionView.insertItems(at: [cellIndexPath])
guard let cellImage = UIImage(systemName: "pencil", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
if indexPath.row == 1 {
print("Passed on row 1")
guard let cellImage = UIImage(systemName: "checkmark", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
}
Still having the same issue "Optional([0, 1])", I decided to give up on this. Thank you very much for your time and effort.
The problem at its' core is "previousViewController.dataPassed = self.collectionViewEffects.indexPathsForSelectedItems?.first" is sending out this info; "Optional([0, 1])" when I tap "indexPath.row = 1", I need to receive only 1 indexPath.row, the one that I tap. That's why "if dataPassed!.row == 1" never gets triggered.class EffectsViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EffectsPhotoSegue" {
if let previousViewController = segue.destination as? PhotoViewController {
previousViewController.dataPassed = self.collectionViewEffects.indexPathsForSelectedItems?.first
}
}
}
}
class PhotoViewController: UIViewController {
var dataPassed: IndexPath?
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == resetConfirmCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResetConfirmCellID", for: indexPath) as! ResetConfirmCell
let config = UIImage.SymbolConfiguration(pointSize: 40, weight: .semibold)
if indexPath.row == 0 {
guard let cellImage = UIImage(systemName: "multiply", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
if indexPath.row == 1 {
print("Passed on row 1")
guard let cellImage = UIImage(systemName: "checkmark", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
if dataPassed!.row == 1 {
let cellCount = resetConfirmCollectionView.visibleCells.count
let item = cellCount - 1
let cellIndexPath = IndexPath(item: item, section: 0)
resetConfirmCollectionView.insertItems(at: [cellIndexPath])
guard let cellImage = UIImage(systemName: "pencil", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
}
}
The breakpoint hits when the "effectsViewController" is about to pop up and I receive the print statement. Then, when I tap in both of the "indexPath.row = 0" && "indexPath.row = 1", the breakpoint hits and I receive the print statement again.
Following up on your guidance I think I'm on the right track. I have removed notifications and added the "dataPassed" variable. I also removed the "effectsMenuCollectionView", instead of that I'm using "resetConfirmCollectionView". Even though I'm tapping on "row = 1" in "collectionViewEffects", I can't trigger the breakpoint I set in line47. Do you see any error or adjustment to be made ? class PhotoViewController: UIViewController, UIScrollViewDelegate {
var dataPassed: IndexPath?
override func viewDidLoad() {
super.viewDidLoad()
resetConfirmCollectionView.reloadData()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "PhotoEffectsSegue" {
if let nextViewController = segue.destination as? EffectsViewController {
DispatchQueue.main.async {
nextViewController.effectsImageView = self.photoImageView
nextViewController.effectsImage = self.filteredImage
nextViewController.pickedEffectsImage = self.pickedImage
}
}
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == resetConfirmCollectionView {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResetConfirmCellID", for: indexPath) as! ResetConfirmCell
let config = UIImage.SymbolConfiguration(pointSize: 40, weight: .semibold)
if indexPath.row == 0 {
guard let cellImage = UIImage(systemName: "multiply", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
if indexPath.row == 1 {
guard let cellImage = UIImage(systemName: "checkmark", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
if dataPassed!.row == 1 {
let cellCount = resetConfirmCollectionView.visibleCells.count
let item = cellCount - 1
let cellIndexPath = IndexPath(item: item, section: 0)
resetConfirmCollectionView.insertItems(at: [cellIndexPath])
guard let cellImage = UIImage(systemName: "pencil", withConfiguration: config) else {
print("SystemImage not available")
return cell
}
cell.resetConfirmImage = cellImage
return cell
}
}
class EffectsViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EffectsPhotoSegue" {
if let previousViewController = segue.destination as? PhotoViewController {
DispatchQueue.main.async {
previousViewController.dataPassed = self.collectionViewEffects.indexPathsForSelectedItems?.first
previousViewController.photoImageView.image = self.effectsImageView!.image
previousViewController.filteredImage = self.effectsImage
previousViewController.pickedImage = self.pickedEffectsImage
previousViewController.effectsSegmentedControl()
(previousViewController.menuStackView).isHidden = true
resetConfirmCollectionView.isHidden = false
}
}
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == collectionViewEffects {
if indexPath.row == 0 {
effectsImageView!.image = pickedEffectsImage
self.performSegue(withIdentifier: "EffectsPhotoSegue", sender: self)
}
if indexPath.row == 1 {
let imageViewHeight: CGFloat = effectsImageView!.image!.size.height
let imageViewWidth: CGFloat = effectsImageView!.image!.size.width
effectsImage = effects.cropToBounds(image: effectsImageView!.image!, width: Double(imageViewWidth), height: Double(imageViewHeight))
self.performSegue(withIdentifier: "EffectsPhotoSegue", sender: self)
}
}
}
I tried that and I've had the same problem because if I'm not mistaken, all the changes must take place within the "@objc func updateCollectionView0(notification: NSNotification)". I think need a way to reach "let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "EffectsMenuCellID", for: indexPath) as! EffectsMenuCell" within @objc func block, then implement an adaptive layout size according to the number of items added and also didSelect for the new item added. I don't know this seems pretty advanced stuff for me.